/*
	Copyright 2008 Marco Mustapic
	
    This file is part of Agilar GWT Widgets.

    Agilar GWT Widgets is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Agilar GWT Widgets is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with Agilar GWT Widgets.  If not, see <http://www.gnu.org/licenses/>.
*/

package org.agilar.gwt.sortabletable;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class TableModel
{
	private List<String> columnNames = new ArrayList<String>();
	private List<Comparator> comparators = new ArrayList<Comparator>();
	private List<List<Object>> data = new ArrayList<List<Object>>();
	
	private int rows = 0;
	private int columns = 0;
	
	public TableModel(int rows, int columns)
	{
		this.rows = rows;
		this.columns = columns;
		
		for (int col=0; col<columns; col++)
		{
			columnNames.add("");
			comparators.add(null);
			data.add(new ArrayList<Object>());
			for (int row=0; row<rows; row++)
			{
				data.get(col).add(null);
			}
		}
	}
	
	public void setColumnName(int column, String name)
	{
		columnNames.set(column, name);
	}
	
	public void setColumnAsSortable(int column, Comparator comparator)
	{
		comparators.set(column, comparator);
	}
	
	public void setColumnAsNonSortable(int column)
	{
		comparators.set(column, null);
	}
	
	public int getColumnCount()
	{
		return columns;
	}
	
	public int getRowCount()
	{
		return rows;
	}
	
	public String getColumnName(int index)
	{
		return columnNames.get(index);
	}
	
	public boolean isColumnSortable(int index)
	{
		return comparators.get(index) != null;
	}
	
	public void set(int row, int column, Object value)
	{
		data.get(column).set(row, value);
	}
	
	public void sort(int column, boolean ascending)
	{
		Comparator comparator = comparators.get(column);
		if (comparator != null)
		{
			qsort(column, comparator, 0, rows-1);
			if (!ascending)
			{
				for (List<Object> list : data)
				{
					Collections.reverse(list);
				}
			}
		}		
	}
	
	private void qsort(int column, Comparator comparator, int left, int right)
	{
		if (left < right)
		{
			int i = partition(column, comparator, left, right);
			qsort(column, comparator, left, i-1);
			qsort(column, comparator, i+1, right);
		}
	}
	
	private int partition(int column, Comparator comparator, int left, int right)
	{
		int i = left - 1;
		int j = right;
		
		while (true)
		{
			while (comparator.compare(data.get(column).get(++i), data.get(column).get(right)) < 0);
			while (comparator.compare(data.get(column).get(right), data.get(column).get(--j)) < 0)
			{
				if (j == left)
				{
					break;
				}
			}
			if (i >= j)
			{
				break;
			}
			
			swapRows(i, j);
		}
		swapRows(i, right);
		
		return i;
	}

	private void swapRows(int i, int j)
	{
		Object aux = null;
		for (List<Object> list : data)
		{
			aux = list.get(i);
			list.set(i, list.get(j));
			list.set(j, aux);
		}
	}

	public Object get(int row, int column)
	{
		return data.get(column).get(row);
	}
}
